package empty

import chipsalliance.rocketchip.config.{Config, Parameters}
import chisel3._
import chisel3.util._
import chisel3.internal.sourceinfo.SourceInfo
import chisel3.stage.ChiselStage
import chisel3.util.random.FibonacciLFSR
import freechips.rocketchip.diplomacy._
import freechips.rocketchip.amba.axi4._
import freechips.rocketchip.tilelink.{TLFilter, TLFuzzer, TLRAMModel, TLToAXI4}
import chisel3.experimental.dataview._
import StandardAXI4BundleBundle._

object myAxiUtil{
//首先是为不同的模块定义不同的参数，diplomacy提供了标准的定义，以供使用
//1. AXI4MasterPortParameters：依赖于AXI4SlaveParameters
//2. AXI4SlavePortParameters：依赖于AXI4MasterParameters
//这一步对应于Add.scala中的三个case class
//这里我们直接继承这些case class并且进行自定义：
// case class myAXI4MasterParameters(name:String="Axi4Master", id:IdRange=IdRange(0,1)) extends AXI4MasterParameters(name, id)
// case class myAXI4MasterPortParameters(masters:Seq[AXI4MasterParameters]=Seq(myAXI4MasterParameters())) extends AXI4MasterPortParameters(masters)
val myAXI4MasterParameters =  AXI4MasterParameters(name="Axi4Master", id=IdRange(0,16))
val myAXI4MasterPortParameters = Seq(AXI4MasterPortParameters(masters=Seq(myAXI4MasterParameters)))

//两个slave，因此定义两个 AXI4SlavePortParameters
// case class myAXI4SlaveParameters1(
//     address: Seq[AddressSet] = Seq(AddressSet(0x80000000L, 0xffff)),
//     supportsWrite : TransferSizes = TransferSizes(64),
//     supportsRead  : TransferSizes = TransferSizes(64)
//     ) extends AXI4SlaveParameters(address=address, supportsWrite=supportsWrite,supportsRead=supportsRead)
// case class myAXI4SlavePortParameters1(slaves:Seq[AXI4SlaveParameters]=Seq(myAXI4SlaveParameters1()), beatBytes:Int=64
//     ) extends AXI4SlavePortParameters(slaves=slaves, beatBytes=beatBytes)
val myAXI4SlaveParameters1 = AXI4SlaveParameters(
    address = Seq(AddressSet(0x80000000L, 0xffff)),
    supportsWrite= TransferSizes(64),
    supportsRead = TransferSizes(64)
    )
val myAXI4SlavePortParameters1 = Seq(AXI4SlavePortParameters(slaves=Seq(myAXI4SlaveParameters1), beatBytes=64))


// case class myAXI4SlaveParameters2(
//     address: Seq[AddressSet] = Seq(AddressSet(0x90000000L, 0xffff)),
//     supportsWrite : TransferSizes = TransferSizes(64),
//     supportsRead  : TransferSizes = TransferSizes(64)
//     ) extends AXI4SlaveParameters(address=address, supportsWrite=supportsWrite,supportsRead=supportsRead)
// case class myAXI4SlavePortParameters2(slaves:Seq[AXI4SlaveParameters]=Seq(myAXI4SlaveParameters2()), beatBytes:Int=64
//     ) extends AXI4SlavePortParameters(slaves=slaves, beatBytes=beatBytes)
val myAXI4SlaveParameters2 = AXI4SlaveParameters(
    address = Seq(AddressSet(0x90000000L, 0xffff)),
    supportsWrite = TransferSizes(64),
    supportsRead  = TransferSizes(64)
    )
val myAXI4SlavePortParameters2 = Seq(AXI4SlavePortParameters(slaves=Seq(myAXI4SlaveParameters2), beatBytes=64))

// case class myAXI4SlaveParameters3(
//     address: Seq[AddressSet] = Seq(AddressSet(0x00000000L, 0xffffffff)),
//     supportsWrite : TransferSizes = TransferSizes(64),
//     supportsRead  : TransferSizes = TransferSizes(64)
//     ) extends AXI4SlaveParameters(address=address, supportsWrite=supportsWrite,supportsRead=supportsRead)
// case class myAXI4SlavePortParameters3(slaves:Seq[AXI4SlaveParameters]=Seq(myAXI4SlaveParameters3()), beatBytes:Int=64
//     ) extends AXI4SlavePortParameters(slaves=slaves, beatBytes=beatBytes)
val myAXI4SlaveParameters3 = AXI4SlaveParameters(
    address = Seq(AddressSet(0x00000000L, 0xffffffffL)),
    supportsWrite = TransferSizes(64),
    supportsRead  = TransferSizes(64)
    )
val myAXI4SlavePortParameters3 = Seq(AXI4SlavePortParameters(slaves=Seq(myAXI4SlaveParameters3), beatBytes=64))

//the mem region for ddr
// val ddrParams = AXI4SlaveParameters(
//     address = Seq(AddressSet(0x00000000L, 0x7fffffffL),
//     AddressSet(0x80000000L, 0x6fffffffL),//8,10,12,14
//     AddressSet(0x90000000L, 0xfffffffL),
//     AddressSet(0xb0000000L, 0xfffffffL),
//     AddressSet(0xd0000000L, 0xfffffffL),
//     AddressSet(0xf0000000L, 0x5fffffL)),
//     supportsWrite = TransferSizes(64),
//     supportsRead  = TransferSizes(64)
//     )
val ddrParams = AXI4SlaveParameters(
    address = AddressSet.misaligned(0x00000000L, 0xffbfffc0L),
    supportsWrite = TransferSizes(64),
    supportsRead  = TransferSizes(64)
    )
val ddrPortParams = Seq(AXI4SlavePortParameters(slaves=Seq(ddrParams), beatBytes=64))
//the mem region for cfg
val cfgParams = AXI4SlaveParameters(
    address = Seq(AddressSet(0xffc00000L, 0x3fffffL)),
    supportsWrite = TransferSizes(64),
    supportsRead  = TransferSizes(64)
    )
val cfgPortParams = Seq(AXI4SlavePortParameters(slaves=Seq(cfgParams), beatBytes=64))
}


//然后是为定义不同类型的node，以便于和后续模块绑定，主要是两个driver模块、xbar模块和一个accept模块
//1. case class AXI4MasterNode(portParams: Seq[AXI4MasterPortParameters])：用于driver模块
//2. case class AXI4SlaveNode(portParams: Seq[AXI4SlavePortParameters])：用于accept模块
//3. case class AXI4NexusNode(
//  masterFn:       Seq[AXI4MasterPortParameters] => AXI4MasterPortParameters,
//  slaveFn:        Seq[AXI4SlavePortParameters]  => AXI4SlavePortParameters)(
//  implicit valName: ValName):用于xbar模块

//编写AXI4Xbar模块，这一步省略，因为rocket chip库中有，并且已经实现了与AXI4NexusNode节点的绑定，对应于Add.scala中的Adder类；

//编写driver模块
class axi4Driver()(implicit valName:ValName, p:Parameters) extends LazyModule {
    import myAxiUtil._
    val node = AXI4MasterNode(myAXI4MasterPortParameters)
    
    lazy val module = new LazyModuleImp (this) {
        //get the bundles and edge, because it is a source node, it has only the outward bundles and edges
		val (io_out, edge) = node.out(0)
		dontTouch(io_out)

	}
	
    override lazy val desiredName = "axi4Driver"
}

//编写accept模块
class axi4Accept()(implicit valName:ValName, p:Parameters) extends  LazyModule {
    import myAxiUtil._
    val node = AXI4SlaveNode(myAXI4SlavePortParameters3)//使用myAXI4SlavePortParameters3，接受32bit的所有参数；

    lazy val module = new LazyModuleImp (this) {
		val (io_in, edge) = node.in(0)
		dontTouch(io_in)
    }
    override lazy val desiredName = "axi4Accept"
}


class axi4sram()(implicit valName:ValName, p:Parameters) extends  LazyModule {
    import myAxiUtil._
    val node = AXI4SlaveNode(ddrPortParams)//使用myAXI4SlavePortParameters3，接受32bit的所有参数；

    lazy val module = new LazyModuleImp (this) {
		val (io_in, edge) = node.in(0)
		dontTouch(io_in)
    }
    override lazy val desiredName = "axi4sram"
}

class axi4cfg()(implicit valName:ValName, p:Parameters) extends  LazyModule {
    import myAxiUtil._
    val node = AXI4SlaveNode(cfgPortParams)//使用myAXI4SlavePortParameters3，接受32bit的所有参数；

    lazy val module = new LazyModuleImp (this) {
		val (io_in, edge) = node.in(0)
		dontTouch(io_in)
    }
    override lazy val desiredName = "axi4cfg"
}


//编写顶层
class xbarTestHarness()(implicit valName:ValName, p:Parameters) extends LazyModule {
    import myAxiUtil._
    val numSlaves = 4
    //two axi4 drivers
    val drivers = Seq.fill(numSlaves){
        LazyModule(new axi4Driver())
    }

    //two axi4 accepter
    val sram = LazyModule(new axi4sram())
    val cfg  = LazyModule(new axi4cfg())

    //axi4 interconnect
    val xbar = AXI4Xbar()//xbar is the node of AXI4Xbar

    //connection between xbar and accepters
    sram.node := xbar
    cfg.node  := xbar
    
    //connection between xbar and drivers
    drivers.zipWithIndex.foreach { case (d, i) => (xbar
      := d.node)
    }

    lazy val module = new LazyModuleImp (this) {

    }
    override lazy val desiredName = "xbarTestHarness"

}

class myAXI4Module() extends Module {
	val myAXI4BundleParameters = new AXI4BundleParameters(addrBits=32, dataBits=512, idBits=7)
	val io = IO(new Bundle {
		//val in = Flipped(new AXI4Bundle(myAXI4BundleParameters))
		val out = new AXI4Bundle(myAXI4BundleParameters)
	})
    //val mem = IO(new StandardAXI4BundleBundle(32, 512, 7))
	io.out <> DontCare
    //io.out := mem.viewAs[AXI4Bundle]
	dontTouch(io.out)
    
}

object AxiMain extends App {
 println("Generating Hardware")
    //implicit val valName:ValName = new ValName("MyAxiCrossbar")
    implicit val p = Parameters.empty
    val verilog = (new ChiselStage).emitVerilog(LazyModule(new xbarTestHarness()).module,Array("--target-dir","generated"))
    //val verilog2 = (new ChiselStage).emitVerilog(LazyModule(new AXI4XbarFuzzTest("Xbar DUT21", 5000, 2,1)).module)
	//val verilog3 = (new ChiselStage).emitVerilog(new myAXI4Module(),Array("--target-dir","generated"))
}
